    //
// Created by 10413 on 2023/3/27.
//

#ifndef NEST_SVGUTIL_HPP
#define NEST_SVGUTIL_HPP
#include "../entity/NestPath.h"
#include "../lib/tinyxml2/tinyxml2.h"
#include "../algorithm/Placement.h"
#include "../algorithm/Nest.h"
#include <fstream>
#include <sstream>
using namespace tinyxml2;
using namespace std;
namespace SVGUtil{

    static void buildPolygonVector(Polygon *polygon,std::vector<double> &x,std::vector<double> &y){
        Vector shiftVector=polygon->offset;
        for(int i=0;i<polygon->lenth;i++){
            x.push_back(polygon->getx(i)+shiftVector.x);
            y.push_back(polygon->gety(i)+shiftVector.y);
        }
        if(polygon->lenth>1){
            x.push_back(polygon->getx(0)+shiftVector.x);
            y.push_back(polygon->gety(0)+shiftVector.y);
        }
        return;
    }

    static vector<NestPath> transferSvgIntoNestPaths(const char *svgPath) {
        vector<NestPath> nestPaths;
        XMLDocument doc;
        doc.LoadFile(svgPath);
        XMLElement* root = doc.RootElement();
        int count = 0;
        for (XMLElement* element = root->FirstChildElement(); element != nullptr; element = element->NextSiblingElement()) {
            count++;
            if (strcmp(element->Name(), "polygon") == 0) {  // 不带孔多边形
                const char* points = element->Attribute("points");
                std::string pointsStr(points);
                std::replace(pointsStr.begin(), pointsStr.end(), '\n', ' ');
                std::replace(pointsStr.begin(), pointsStr.end(), '\t', ' ');

                Polygon *polygon = new Polygon();
                std::istringstream iss(pointsStr);
                std::string s;
                while (getline(iss, s, ' ')) {
                    size_t commaPos = s.find(',');
                    if (commaPos != std::string::npos) {
                        double x = std::stod(s.substr(0, commaPos));
                        double y = std::stod(s.substr(commaPos + 1));
//                        cout<<x<<" "<<y<<endl;
                        polygon->add(x,y);
                    }
                }
                NestPath nestPath;
                nestPath.push_back(polygon);
                nestPaths.push_back(nestPath);
            } else if (strcmp(element->Name(), "rect") == 0) {
                double width = stod(element->Attribute("width"));
                double height = stod(element->Attribute("height"));
                double x = stod(element->Attribute("x"));
                double y = stod(element->Attribute("y"));
                Polygon* rect = new Polygon();
                rect->add(x, y);
                rect->add(x + width, y);
                rect->add(x + width, y + height);
                rect->add(x, y + height);
                NestPath nestPath;
                nestPath.push_back(rect);
                nestPaths.push_back(nestPath);
            } else if (strcmp(element->Name(), "path") == 0) {
                const char* d = element->Attribute("d");
                std::string dStr(d);
                std::replace(dStr.begin(), dStr.end(), '\n', ' ');
                std::replace(dStr.begin(), dStr.end(), '\t', ' ');
                // 将连续的多个逗号合并成一个逗号
                std::string::iterator new_end = std::unique(dStr.begin(), dStr.end(), [](const char& lhs, const char& rhs) {
                    return (lhs == rhs) && (lhs == ',');
                });
                dStr.erase(new_end, dStr.end());
                NestPath nestPath;
                Polygon* polygon = new Polygon();
                std::istringstream iss(dStr);
                std::string cmd, s;
                double x = 0.0, y = 0.0;
                bool newPath = false;

                while (!iss.eof()) {
                    cmd = iss.get();
                    if (cmd == "M") {  // 起始点
                        iss >> s;
                        size_t commaPos = s.find(',');
                        if (commaPos != std::string::npos) {
                            x = std::stod(s.substr(0, commaPos));
                            y = std::stod(s.substr(commaPos + 1));
                            polygon->add(x, y);
                        }
                    } else if (cmd == "L") {  //接下来的路径
                        while (getline(iss, s, ' ')) {
                            size_t commaPos = s.find(',');
                            if (commaPos != std::string::npos) {
                                double x = std::stod(s.substr(0, commaPos));
                                string secondStr = s.substr(commaPos + 1);
                                if(s.find('Z')!=std::string::npos){  // 针对L90,10 90,90 10,90Z 这种情况
                                    secondStr = secondStr.substr(0, secondStr.length() - 1); // 去掉z
                                    newPath = true;
                                }
                                double y = std::stod(secondStr);
//                                cout<<x<<" "<<y<<endl;
                                polygon->add(x,y);
                                if (newPath){
                                    newPath = false;
                                    nestPath.push_back(polygon);
                                    polygon = new Polygon();
                                    break;
                                }
                            }
                        }
                    } else if (cmd == "Z") {  // 结束点 针对10,90 Z 有空格这种情况
                        nestPath.push_back(polygon);
                        polygon = new Polygon();
                    } else if (cmd == " ") {
                        continue;
                    } else {
                        cout << "Unknown command: " << cmd << endl;
                    }
                }
                nestPaths.push_back(nestPath);
            }


        }
        return nestPaths;
    }

    // todo: 是不是要返回指针
    static string svgGenerator(NestPath &bin, Individual &individual) {
        std::vector<NestPath> parts=individual.paths;
        std::vector<Vector> placement=individual.placement;
        std::string s;
        for (int i = 0; i < bin.size(); i++) {
            std::vector<double> x;
            std::vector<double> y;
            Polygon *polygon=bin[i];
            // todo: 如果不用Matplotlib画图了，需要把这个函数改一改，去掉在polygon末尾加入起始点，然后把下面的x.size()-1改为x.size()
            buildPolygonVector(polygon,x,y);
            s += "<polygon points=\"";
            for(int j = 0; j < x.size()-1; j++) {
                s += std::to_string(x[j]) + "," + std::to_string(y[j]) + " ";
            }
            s += "\" fill=\"none\" stroke=\"#010101\" stroke-width=\"0.1\" />\n";
        }
        for(int i=0;i<parts.size();i++){
            // todo: 输出带孔洞的多边形，需要填充。
            NestPath path=parts[i];
            int angle=path.rotation;
            for(int j=0;j<path.size();j++){
                std::vector<double> x;
                std::vector<double> y;
                Polygon *polygon=GeometryUtils::rotatePolygon(path[j],angle);
                polygon->offset=placement[i];
                buildPolygonVector(polygon,x,y);
                s += "<path d=\"";
                for(int k=0; k < x.size()-1; k++) {
                    if(k == 0) {
                        s += "M";
                    } else if (k == 1){
                        s += "L";
                    }
                    s += std::to_string(x[k]) + "," + std::to_string(y[k]) + " ";
                }
                s += "Z\" fill=\"#8498d1\" stroke=\"#010101\" stroke-width=\"0.1\" />\n";
            }
        }
        return s;
    }


    static void saveSvgFile(const string& s, const string& filename) {
        ofstream outfile(filename);
        outfile << R"(<?xml version="1.0" standalone="no"?>)" << endl
                << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \n"
                << "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"
                << "<svg viewBox=\"0 0  500 500\" width=\"100%\" height=\"600px\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n";
        outfile << s << endl;
        outfile << "</svg>";
        outfile.close();
    }

}
#endif //NEST_SVGUTIL_HPP
